home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-19 / iritsm3s.zip / CAGDSWEP.C < prev    next >
C/C++ Source or Header  |  1991-12-01  |  11KB  |  299 lines

  1. /******************************************************************************
  2. * CagdSwep.c - Sweep srf operator out of given cross section and an axis.     *
  3. *******************************************************************************
  4. * Written by Gershon Elber, May. 91.                          *
  5. ******************************************************************************/
  6.  
  7. #ifdef __MSDOS__
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <alloc.h>
  11. #endif /* __MSDOS__ */
  12.  
  13. #include "cagd_loc.h"
  14.  
  15. static void TransformCrossSection(CagdRType **SPoints, int Index,
  16.               CagdCrvStruct *CrossSection, CagdRType *Position,
  17.               CagdRType Scale, CagdVecStruct *Tangent,
  18.               CagdVecStruct *Normal);
  19. static void GenTransformMatrix(CagdMatStruct *Mat, CagdRType *Trans,
  20.                    CagdVecStruct *Normal, CagdVecStruct *Dir,
  21.                    CagdRType Scale);
  22.  
  23. /******************************************************************************
  24. * Constructs a sweep surface using the following curves:                      *
  25. * 1. CrossSection - defines the basic cross section of the sweep. Must be in  *
  26. *    the XY plane.                                  *
  27. * 2. Axis - a 3D curve the CrossSection will be swept along such that the     *
  28. *    Axis normal aligns with the Y axis of the cross section. If Axis is      *
  29. *    linear (i.e. no normal), the normal is picked randomly or to fit the non *
  30. *    linear part of the Axis (if any).                          *
  31. * 3. Scale - a scaling curve for the sweep, If NULL a scale of Scale is used. *
  32. ******************************************************************************/
  33. CagdSrfStruct *CagdSweepSrf(CagdCrvStruct *CrossSection, CagdCrvStruct *Axis,
  34.                     CagdCrvStruct *ScalingCrv, CagdRType Scale)
  35. {
  36.     CagdSrfStruct *Srf;
  37.     CagdVecStruct Normal, *Vec, TVec;
  38.     CagdPointType
  39.     SrfPType = CAGD_PT_E3_TYPE;
  40.     CagdGeomType
  41.     SrfGType = CAGD_SBSPLINE_TYPE;
  42.     int i, j, k,
  43.     ULength = CrossSection -> Length,
  44.     VLength = Axis -> Length,
  45.     UOrder = CrossSection -> Order,
  46.     VOrder = Axis -> Order;
  47.     CagdRType **Points, *AxisNodes, *AxisNodePtr, *AxisKV,
  48.     *AxisWeights = NULL;
  49.  
  50.     switch (Axis -> GType) {
  51.     case CAGD_CBEZIER_TYPE:
  52.         SrfGType = CAGD_SBEZIER_TYPE;
  53.         AxisKV = BspKnotUniformOpen(VLength, VOrder, NULL);
  54.         AxisNodes = AxisNodePtr = BspKnotNodes(AxisKV,
  55.                            VLength + VOrder,
  56.                            VOrder);
  57.         break;
  58.     case CAGD_CBSPLINE_TYPE:
  59.         SrfGType = CAGD_SBSPLINE_TYPE;
  60.         AxisKV = Axis -> KnotVector;
  61.         AxisNodePtr = AxisNodes = BspKnotNodes(Axis -> KnotVector,
  62.                            VLength + VOrder,
  63.                            VOrder);
  64.         break;
  65.     case CAGD_CPOWER_TYPE:
  66.         FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
  67.         break;
  68.     default:
  69.         FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
  70.         break;
  71.     }
  72.     if (CAGD_IS_RATIONAL_CRV(Axis)) AxisWeights = Axis -> Points[W];
  73.  
  74.     switch (CrossSection -> GType) {
  75.     case CAGD_CBEZIER_TYPE:
  76.         break;
  77.     case CAGD_CBSPLINE_TYPE:
  78.         SrfGType = CAGD_SBSPLINE_TYPE;
  79.         break;
  80.     case CAGD_CPOWER_TYPE:
  81.         FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
  82.         break;
  83.     default:
  84.         FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
  85.         break;
  86.     }
  87.  
  88.     if (ScalingCrv) {
  89.     int ScaleKVLen,
  90.         AxisKVLen = Axis -> Order + Axis -> Length;
  91.  
  92.     switch (ScalingCrv -> GType) {
  93.         case CAGD_CBEZIER_TYPE:
  94.         ScalingCrv = CnvrtBezier2BsplineCrv(ScalingCrv);
  95.             break;
  96.         case CAGD_CBSPLINE_TYPE:
  97.             ScalingCrv = CagdCrvCopy(ScalingCrv);
  98.         break;
  99.         case CAGD_CPOWER_TYPE:
  100.         FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
  101.         break;
  102.         default:
  103.         FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
  104.         break;
  105.     }
  106.  
  107.     ScaleKVLen = ScalingCrv -> Order + ScalingCrv -> Length;
  108.  
  109.         /* Affine trans. ScalingCrv KV to match Axis. */
  110.     BspKnotAffineTrans(ScalingCrv -> KnotVector, ScaleKVLen,
  111.                AxisKV[0] - ScalingCrv -> KnotVector[0],
  112.                (AxisKV[AxisKVLen - 1] - AxisKV[0]) /
  113.                (ScalingCrv -> KnotVector[ScaleKVLen - 1] -
  114.                 ScalingCrv -> KnotVector[0]));
  115.     }
  116.  
  117.     if (CAGD_IS_RATIONAL_CRV(Axis) || CAGD_IS_RATIONAL_CRV(CrossSection))
  118.     SrfPType = CAGD_PT_P3_TYPE;
  119.  
  120.     switch (SrfGType) {
  121.     case CAGD_SBEZIER_TYPE:
  122.         Srf = BzrSrfNew(ULength, VLength, SrfPType);
  123.         break;
  124.     case CAGD_SBSPLINE_TYPE:
  125.         Srf = BspSrfNew(ULength, VLength, UOrder, VOrder, SrfPType);
  126.         if (CrossSection -> GType == CAGD_CBSPLINE_TYPE)
  127.         GEN_COPY(Srf -> UKnotVector, CrossSection -> KnotVector,
  128.                 sizeof(CagdRType) * (ULength + UOrder));
  129.         else
  130.         BspKnotUniformOpen(ULength, UOrder, Srf -> UKnotVector);
  131.         if (Axis -> GType == CAGD_CBSPLINE_TYPE)
  132.         GEN_COPY(Srf -> VKnotVector, Axis -> KnotVector,
  133.                 sizeof(CagdRType) * (VLength + VOrder));
  134.         else
  135.         BspKnotUniformOpen(VLength, VOrder, Srf -> VKnotVector);
  136.         break;
  137.     default:
  138.         FATAL_ERROR(CAGD_ERR_UNDEF_SRF);
  139.         break;
  140.     }
  141.     Points = Srf -> Points;
  142.  
  143.     /* Compute the normal to the axis curve and use it to align the +Y axis  */
  144.     /* of the cross section with that vector. If the Axis curve has no       */
  145.     /* normal (i.e. it is a linear segment), an arbitrary normal is picked.  */
  146.     Vec = CagdCrvNormal(Axis, *AxisNodePtr);
  147.     if (Vec != NULL) {
  148.     CAGD_COPY_VECTOR(Normal, *Vec);
  149.     }
  150.     else {
  151.     Vec = CagdCrvTangent(Axis, *AxisNodePtr);
  152.     Normal.Vec[0] = Normal.Vec[1] = Normal.Vec[2] = 0.0;
  153.     if (ABS(Vec -> Vec[0]) <= ABS(Vec -> Vec[1]) &&
  154.         ABS(Vec -> Vec[0]) <= ABS(Vec -> Vec[2]))
  155.         Normal.Vec[0] = 1.0;
  156.     else if (ABS(Vec -> Vec[1]) <= ABS(Vec -> Vec[0]) &&
  157.          ABS(Vec -> Vec[1]) <= ABS(Vec -> Vec[2]))
  158.         Normal.Vec[1] = 1.0;
  159.     else
  160.         Normal.Vec[2] = 1.0;
  161.  
  162.     CROSS_PROD(TVec.Vec, Vec -> Vec, Normal.Vec);
  163.     CAGD_NORMALIZE_VECTOR(TVec);
  164.     CROSS_PROD(Normal.Vec, TVec.Vec, Vec -> Vec);
  165.     }
  166.  
  167.     /* For each ctl points of the axis, transform the cross section          */
  168.     /* according to ctl point position, tangent to axis at the point and in  */
  169.     /* such a way to minimize Normal change.                     */
  170.     for (i = 0; i < VLength; i++) {
  171.     CagdRType PosE3[3], ScaleE2[2],
  172.         *Scaling = ScalingCrv ? CagdCrvEval(ScalingCrv, *AxisNodePtr) : NULL;
  173.     CagdVecStruct
  174.         *Tangent = CagdCrvTangent(Axis, *AxisNodePtr++);
  175.  
  176.     if (Scaling)
  177.         CagdCoerceToE2(ScaleE2, &Scaling, -1, ScalingCrv -> PType);
  178.     else
  179.         ScaleE2[1] = Scale;
  180.     if (AxisWeights) ScaleE2[1] /= AxisWeights[i];
  181.  
  182.     CagdCoerceToE3(PosE3, Axis -> Points, i, Axis -> PType);
  183.     TransformCrossSection(Points, i * ULength, CrossSection,
  184.                   PosE3, ScaleE2[1], Tangent, &Normal);
  185.     }
  186.  
  187.     /* Do fixups if axis is a rational curve (note surface is P3). */
  188.     if (AxisWeights) {
  189.     if (CAGD_IS_RATIONAL_CRV(CrossSection)) {
  190.         /* Need only scale by the Axis curve weights: */
  191.         for (j = 0, k = 0; j < VLength; j++)
  192.         for (i = 0; i < ULength; i++, k++) {
  193.             Points[X][k] *= AxisWeights[j];
  194.             Points[Y][k] *= AxisWeights[j];
  195.             Points[Z][k] *= AxisWeights[j];
  196.             Points[W][k] *= AxisWeights[j];
  197.         }
  198.     }
  199.     else {
  200.         /* Weights do not exists at the moment - need to copy them. */
  201.         for (j = 0, k = 0; j < VLength; j++)
  202.         for (i = 0; i < ULength; i++, k++) {
  203.             Points[X][k] *= AxisWeights[j];
  204.             Points[Y][k] *= AxisWeights[j];
  205.             Points[Z][k] *= AxisWeights[j];
  206.             Points[W][k] = AxisWeights[j];
  207.         }
  208.     }
  209.     }
  210.  
  211.     if (Axis -> GType == CAGD_CBEZIER_TYPE)
  212.         CagdFree((VoidPtr) AxisKV);
  213.     if (ScalingCrv)
  214.     CagdCrvFree(ScalingCrv);
  215.     CagdFree((VoidPtr) AxisNodes);
  216.  
  217.     return Srf;
  218. }
  219.  
  220. /******************************************************************************
  221. * Transform The CrossSection Points, to Position such that Tangent is         *
  222. * perpendicular to the cross section (which is assumed to be on the XY        *
  223. * plane). The +Y axis of the cross section is aligned with Normal direction   *
  224. * to minimize twist along the sweep and been updated to new normal.          *
  225. *   Transformed cross section is place into srf Points, SPoints starting from *
  226. * index SIndex.                                      *
  227. *   All agrument vectors are assumed to be normalized to a unit length.          *
  228. ******************************************************************************/
  229. static void TransformCrossSection(CagdRType **SPoints, int SIndex,
  230.               CagdCrvStruct *CrossSection, CagdRType *Position,
  231.               CagdRType Scale, CagdVecStruct *Tangent,
  232.               CagdVecStruct *Normal)
  233. {
  234.     CagdPointType
  235.     PType = CrossSection -> PType;
  236.     CagdBType
  237.     IsNotRational = !CAGD_IS_RATIONAL_PT(PType);
  238.     CagdVecStruct TVec;
  239.     CagdMatStruct Mat;
  240.     CagdCrvStruct
  241.     *CSCopy = CagdCrvCopy(CrossSection);
  242.     int i, j,
  243.     MaxCoord = CAGD_NUM_OF_PT_COORD(PType),
  244.     Len = CSCopy -> Length;
  245.     CagdRType R,
  246.     **CSPoints = CSCopy -> Points;
  247.  
  248.     /* Fix the Normal to be perpendicular to the Tangent vector is a minimal */
  249.     /* rotation. This ensures minimal twist in the resulting surface.         */
  250.     R = DOT_PROD(Normal -> Vec, Tangent -> Vec);
  251.     TVec = *Tangent;
  252.     CAGD_MULT_VECTOR(TVec, R);
  253.     CAGD_SUB_VECTOR(*Normal, TVec);
  254.     CAGD_NORMALIZE_VECTOR(*Normal);
  255.  
  256.     GenTransformMatrix(&Mat, Position, Normal, Tangent, Scale);
  257.     CagdCrvMatTransform(CSCopy, &Mat);
  258.  
  259.     for (i = 0; i < Len; i++)
  260.     for (j = IsNotRational; j <= MaxCoord; j++)
  261.         SPoints[j][SIndex + i] = CSPoints[j][i];
  262.  
  263.     CagdCrvFree(CSCopy);
  264. }
  265.  
  266. /******************************************************************************
  267. *   Routine to preper transformation martix to do the following (in this      *
  268. * order): scale by Scale, rotate such that the Z axis is in direction Dir     *
  269. * and Y is colinear with the Normal and then translate by Trans.          *
  270. *    Algorithm: given the Trans vector, it forms the 4th line of Mat. Dir is  *
  271. * used to form the second line (the first 3 lines set the rotation), and      *
  272. * finally Scale is used to scale first 3 lines/columns to the needed scale:   *
  273. *                |  Tx  Ty  Tz  0 |   A transformation which takes the coord  *
  274. *                |  Bx  By  Bz  0 |  system into T, N & B as required and     *
  275. * [X  Y  Z  1] * |  Nx  Ny  Nz  0 |  then translate it to C. T, N, B are      *
  276. *                |  Cx  Cy  Cz  1 |  scaled by Scale.                  *
  277. * N is exactly Dir (unit vec). T is set to be the Normal and B their cross    *
  278. * product.                                      *
  279. *   All agrument vectors are assumed to be normalized to a unit length.          *
  280. ******************************************************************************/
  281. static void GenTransformMatrix(CagdMatStruct *Mat, CagdRType *Trans,
  282.                    CagdVecStruct *Normal, CagdVecStruct *Dir,
  283.                    CagdRType Scale)
  284. {
  285.     int i;
  286.     CagdVecStruct B;
  287.  
  288.     CROSS_PROD(B.Vec, Dir -> Vec, Normal -> Vec);
  289.  
  290.     for (i = 0; i < 3; i++) {
  291.     Mat -> Mat[0][i] = Normal -> Vec[i] * Scale;
  292.     Mat -> Mat[1][i] = B.Vec[i] * Scale;
  293.     Mat -> Mat[2][i] = Dir -> Vec[i] * Scale;
  294.     Mat -> Mat[3][i] = Trans[i];
  295.     Mat -> Mat[i][3] = 0.0;
  296.     }
  297.     Mat -> Mat[3][3] = 1.0;
  298. }
  299.